home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_068 / mg1b / tty / amiga / ttymenu.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  15KB  |  513 lines

  1. /*
  2.  * ttymenu.c
  3.  *
  4.  * Incorporates the browser, for rummaging around on disks,
  5.  * and the usual Emacs editing command menu
  6.  *
  7.  *    Copyright (c) 1986, Mike Meyer
  8.  *    Manxification and Edit menu by Mic Kaczmarczik (no charge :-)
  9.  *
  10.  * Permission is hereby granted to distribute this program, so long as
  11.  * this source file is distributed with it, and this copyright notice
  12.  * is not removed from the file.
  13.  *
  14.  */
  15.  
  16. #include <exec/types.h>
  17. #include <libraries/dos.h>
  18. #include <libraries/dosextens.h>
  19. #include <intuition/intuition.h>
  20. #undef    TRUE
  21. #undef    FALSE
  22. #include "def.h"
  23.  
  24. extern struct Menu        *AutoMenu ;
  25. extern struct Window        *EmW ;
  26.  
  27. #ifdef    LATTICE
  28. static VOID    Add_Devices(ULONG) ;
  29. #else
  30. static VOID    Add_Devices() ;
  31. #endif
  32.  
  33. #define MNUM(menu,item,sub) (SHIFTMENU(menu)|SHIFTITEM(item)|SHIFTSUB(sub))
  34.  
  35. #ifdef    BROWSER
  36. #define LONGEST_NAME    80    /* Longest file name we can deal with    */
  37.  
  38. # ifdef    LATTICE
  39. char *strchr(char *, int);
  40. # else
  41. char *index();            /* find first instance of c in s    */
  42. #define    strchr(s, c) index(s, c)
  43. # endif
  44.  
  45. # ifdef    MENU
  46. #define    FIRSTMENU    1
  47. # else
  48. #define    FIRSTMENU    0
  49. # endif
  50.  
  51. #endif    BROWSER
  52.  
  53. #ifdef    MENU
  54. /*
  55.  * When ttgetc() sees a menu selection event, it stuffs
  56.  * the sequence <CSI>M~ into the input buffer, and
  57.  * caches the menu number and item number for later.
  58.  * This sequence is translated into the internal key code
  59.  * KMENU, similar to KHELP and the other function keys.
  60.  *
  61.  * The menu item names are chosen to be relatively close
  62.  * to the extended function names, so a user can usually
  63.  * figure out the key binding of a menu item by searching
  64.  * through the "display-bindings" buffer for something
  65.  * that's close.
  66.  */
  67.  
  68. /*
  69.  * Commands for managing files and buffers
  70.  */
  71.  
  72. static struct MenuBinding FileItems[] = {
  73.     { "Find File         C-x C-f",    "find-file"            },
  74.     { "Pop To File       C-x 4 f",    "find-file-other-window"    },
  75.     { "Insert File       C-x i",    "insert-file"            },
  76.     { "Save File         C-x C-s",    "save-buffer"            },
  77.     { "Write File        C-x C-w",    "write-file"            },
  78.     { "Switch To Buffer  C-x b",    "switch-to-buffer"        },
  79.     { "Pop To Buffer     C-x 4 b",    "switch-to-buffer-other-window"    },
  80.     { "Kill Buffer       C-x k",    "kill-buffer"            },
  81.     { "List Buffers      C-x C-b",    "list-buffers"            },
  82.     { "Save Buffers      C-x s",    "save-some-buffers"        },
  83.     { "Save And Exit     C-x C-c",    "save-buffers-kill-emacs"    }
  84. };
  85.  
  86. /*
  87.  * Commands for various editing functions
  88.  */
  89.  
  90. static struct MenuBinding EditItems[] = {
  91.     { "Yank                 C-y",    "yank"                },
  92.     { "Blank Line           C-o ",    "open-line"            },
  93.     { "Kill Line            C-k",    "kill-line"            },
  94.     { "Delete Blank Lines   C-x C-o","delete-blank-lines"        },
  95.     { "Delete Blanks        M-SPC",    "just-one-space"        },
  96.     { "Newline And Indent   C-j",    "newline-and-indent"        },
  97.     { "Transpose Characters C-t",    "transpose-chars"        },
  98.     { "Quoted Insert        C-q",    "quoted-insert"            }
  99. };
  100.  
  101. /*
  102.  * Movement commands
  103.  */
  104.  
  105. static struct MenuBinding MoveItems[] = {
  106.     { "Scroll Up       C-v",    "scroll-up"            },
  107.     { "Scroll Down     M-v",    "scroll-down"            },
  108.     { "Start Of Line   C-a",    "beginning-of-line"        },
  109.     { "Start Of Buffer M-<",    "beginning-of-buffer"        },
  110.     { "End Of Line     C-e",    "end-of-line"            },
  111.     { "End Of Buffer   M->",    "end-of-buffer"            },
  112.     { "Goto Line",            "goto-line"            },
  113.     { "Show Cursor     C-x =",    "what-cursor-position"        }
  114. };
  115.  
  116. /*
  117.  * Commands for searching and replacing
  118.  */
  119.  
  120. static struct MenuBinding SearchItems[] = {
  121.     { "I-Search Forward  C-s",    "isearch-forward"    },
  122.     { "I-Search Backward C-r",    "isearch-backward"    },
  123.     { "Search Again",        "search-again"        },
  124.     { "Search Forward    M-s",    "search-forward"    },
  125.     { "Search Backward   M-r",    "search-backward"    },
  126.     { "Query Replace     M-%",    "query-replace"        }
  127. };
  128.  
  129. /*
  130.  * Commands that manipulate words
  131.  */
  132. static struct MenuBinding WordItems[] = {
  133.     { "Forward Word       M-f",    "forward-word"            },
  134.     { "Backward Word      M-b",    "backward-word"            },
  135.     { "Kill Word          M-d",    "kill-word"             },
  136.     { "Backward Kill Word M-DEL",    "backward-kill-word"         },
  137.     { "Capitalize Word    M-c",    "capitalize-word"        },
  138.     { "Downcase Word      M-l",    "downcase-word"            },
  139.     { "Upcase Word        M-u",    "upcase-word"            }
  140. };
  141.  
  142. static struct MenuBinding ParaItems[] = {
  143.     { "Forward Paragraph  M-]",    "forward-paragraph"        },
  144.     { "Backward Paragraph M-[",    "backward-paragraph"        },
  145.     { "Fill Paragraph     M-q",    "fill-paragraph"        },
  146.     { "Set Fill Column    C-x f",    "set-fill-column"        },
  147.     { "Kill Paragraph",        "kill-paragraph"        },
  148.     { "Auto Fill Mode",        "auto-fill-mode"        }
  149. };
  150.  
  151. /*
  152.  * Region stuff
  153.  */
  154.  
  155. static struct MenuBinding RegionItems[] = {
  156.     { "Set Mark            C-@",    "set-mark-command"        },
  157.     { "Exch Point And Mark C-x C-x","exchange-point-and-mark"    },
  158.     { "Kill Region         C-w",    "kill-region"            },
  159.     { "Copy Region As Kill M-w",    "copy-region-as-kill"        },
  160.     { "Downcase Region     C-x C-l","downcase-region"        },
  161.     { "Upcase Region       C-x C-u","upcase-region"            }
  162. };
  163.  
  164. /*
  165.  * Commands for manipulating windows
  166.  */
  167.  
  168. static struct MenuBinding WindowItems[] = {
  169.     { "Split Window         C-x 2", "split-window-vertically"    },
  170.     { "Delete Window        C-x 0",    "delete-window"            },
  171.     { "Delete Other Windows C-x 1",    "delete-other-windows"        },
  172.     { "Down Window          C-x o",    "next-window"            },
  173.     { "Up Window",            "previous-window"        },
  174.     { "Enlarge Window       C-x ^",    "enlarge-window"        },
  175.     { "Shrink Window",        "shrink-window"            },
  176.     { "Redraw Display",        "redraw-display"        },
  177.     { "Recenter             C-l",    "recenter"            },
  178.     { "Toggle Border",        "toggle-window-hack"        },
  179. #ifdef    CHANGE_FONT
  180.     { "Set Font",            "set-font"            }
  181. #endif
  182. };
  183.  
  184. /*
  185.  * Miscellaneous commands
  186.  */
  187.  
  188. static struct MenuBinding MiscItems[] = {
  189.     { "Start Kbd Macro   C-x (",    "start-kbd-macro"        },
  190.     { "End Kbd Macro     C-x )",    "end-kbd-macro"            },
  191.     { "Call Kbd Macro    C-x e",    "call-last-kbd-macro"        },
  192.     { "Execute Command   M-x",    "execute-extended-command"    },
  193.     { "Global Set Key",        "global-set-key"        },
  194.     { "Global Unset Key",        "global-unset-key"        },
  195.     { "Describe Key      C-h c",    "describe-key-briefly",        },
  196.     { "Describe Bindings C-h b",    "describe-bindings"        },
  197.     { "Emacs Version",        "emacs-version"            },
  198.     { "New CLI           C-z",    "suspend-emacs"            }
  199. };
  200.  
  201. /*
  202.  * The following table contains the titles, number of
  203.  * items, and pointers to, the individual menus.
  204.  */
  205.  
  206. static struct MenuInfo EMInfo[] = {
  207.     { "File  ",        NITEMS(FileItems),    &FileItems[0]    },
  208.     { "Edit  ",        NITEMS(EditItems),    &EditItems[0]    },
  209.     { "Move  ",         NITEMS(MoveItems),    &MoveItems[0]    },
  210.     { "Search  ",        NITEMS(SearchItems),    &SearchItems[0] },
  211.     { "Word  ",        NITEMS(WordItems),    &WordItems[0]    },
  212.     { "Paragraph  ",    NITEMS(ParaItems),    &ParaItems[0]    },
  213.     { "Region  ",        NITEMS(RegionItems),    &RegionItems[0]    },
  214.     { "Window  ",        NITEMS(WindowItems),    &WindowItems[0] },
  215.     { "Miscellaneous  ",    NITEMS(MiscItems),    &MiscItems[0]    }
  216. };
  217.  
  218. /* There are three cases to deal with; the menu alone, the Browser
  219.  * alone, and both of them together.  We #define some things to make
  220.  * life a little easier to deal with
  221.  */
  222. # ifdef    BROWSER
  223. #  define Edit_Menu_Init() Menu_Add("Edit ", TRUE) 
  224. #  define Edit_Menu_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
  225. #  define Edit_Item_Add(n) Menu_SubItem_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
  226. # else
  227. #  define Edit_Menu_Init() cinf = NULL    /* harmless */
  228. #  define Edit_Menu_Add(n) n[strlen(n)-1] = '\0'; Menu_Add(n, TRUE)
  229. #  define Edit_Item_Add(n) Menu_Item_Add(n,(USHORT)ITEMENABLED,0L,(BYTE)0)
  230. # endif    BROWSER
  231.  
  232. #endif    MENU
  233.  
  234. /*
  235.  * Heeere we go!!!!
  236.  */
  237.  
  238. struct Menu * InitEmacsMenu(EmW)
  239. struct Window *EmW;
  240. {
  241. #ifdef    MENU
  242.     register struct MenuInfo *cinf;
  243.     register struct MenuBinding *lastbinding, *cb;
  244.     struct MenuInfo *lastinfo;
  245. #endif
  246.  
  247.     Menu_Init() ;            /* init the menu        */
  248.  
  249. #ifdef    MENU
  250.     Edit_Menu_Init() ;        /* Set up for editing menu    */
  251.     lastinfo = &EMInfo[NITEMS(EMInfo)];    /* loop sentinel    */    
  252.     for (cinf = EMInfo; cinf < lastinfo; cinf++) {
  253.         Edit_Menu_Add(cinf->Name);
  254.         lastbinding = &cinf->Items[cinf->NumItems];
  255.         for (cb = cinf->Items; cb < lastbinding; cb++)
  256.             Edit_Item_Add(cb->Command);
  257.     }
  258. #endif    MENU
  259.  
  260. #ifdef    BROWSER
  261.     Menu_Add("Disks ", TRUE) ;
  262.     Add_Devices(DLT_DEVICE);    /* devices first */
  263.     Add_Devices(DLT_VOLUME);    /* mounted volume names next */
  264.     Add_Devices(DLT_DIRECTORY);    /* assigned directories last */
  265. #endif    BROWSER
  266.     return     AutoMenu ;
  267. }
  268.  
  269. /*
  270.  * amigamenu() -- handles a menu pick.
  271.  */
  272.  
  273. amigamenu(f, n, k) {
  274.     unsigned short        Menu_Number;
  275.     char            *name;
  276.     int            ttmenu(); /* in ttyio.c */
  277.  
  278. #ifdef    BROWSER
  279.     register unsigned short    level, i, dirp;
  280.     register char        *cp;
  281.     int            stat;
  282.     struct MenuItem        *ItemAddress() ;
  283.  
  284.     /* State variables that describe the current directory */
  285.     static char        Dir_Name[LONGEST_NAME] ;
  286.     static unsigned short    Menu_Level = 0 ;
  287. #endif
  288. #ifdef    MENU
  289.     SYMBOL    *sp;
  290. #endif
  291.  
  292.     if (!ttmenu(&Menu_Number)) return FALSE;    /* get menu number */
  293.  
  294. #ifndef    BROWSER
  295. # ifdef    MENU
  296.     name = EMInfo[MENUNUM(Menu_Number)].Items[ITEMNUM(Menu_Number)].Binding;
  297.     if ((sp=symlookup(name)) != NULL)
  298.         return ((*sp->s_funcp)(f, n, KRANDOM));
  299.     panic("amigamenu: unknown menu command!");    /* trouble!    */
  300. # endif
  301. #else    /* we're using the Browser */
  302. # ifdef    MENU
  303.     /* Handle commands from the Edit menu when using the Browser */
  304.     if (0 == MENUNUM(Menu_Number)) {
  305.         name = EMInfo[ITEMNUM(Menu_Number)].Items[SUBNUM(Menu_Number)].Binding;
  306.         if ((sp=symlookup(name)) != NULL)
  307.             return ((*sp->s_funcp)(f, n, KRANDOM));
  308.         panic("Unknown menu command!");    /* trouble!    */
  309.     }
  310. # endif
  311.     /* Here when a selection was made in a Browser menu */
  312.     name = (char *)((struct IntuiText *)
  313.         (ItemAddress(AutoMenu,(ULONG) Menu_Number) -> ItemFill))
  314.         -> IText ;
  315.     level = MENUNUM(Menu_Number) - FIRSTMENU;
  316.  
  317.     /* Got what we want, so clear the menu to avoid confusing the user */
  318.     ClearMenuStrip(EmW) ;
  319.  
  320.     /* set dirp to FALSE if the name is not a directory or disk */
  321.     dirp = (strchr(name, '/') != NULL || strchr(name, ':') != NULL) ;
  322.  
  323.     /* First, set the directory name right */
  324.     if (level > Menu_Level)            /* Not possible, die */
  325.         panic("impossible menu_level in amigamenu");
  326.     else if (level == 0)            /* picked a new disk */
  327.         Dir_Name[0] = '\0' ;
  328.     else if (level < Menu_Level) {        /* Throw away some levels */
  329.         for (i = 1, cp = strchr(Dir_Name, ':'); i < level; i++) {
  330.             if (cp == NULL) return FALSE;
  331.             cp = strchr(cp, '/') ;
  332.             }
  333.         if (cp == NULL) panic("broken file name in amigamenu");
  334.         *++cp = '\0' ;
  335.         }
  336.     /* else Menu_Level == level, chose a file a current level */
  337.  
  338.     /* Now, fix up the menu and it's state variable */
  339.     while (Menu_Level > level) {
  340.         Menu_Level-- ;
  341.         Menu_Pop() ;
  342.         }
  343.  
  344.     /* If we added a file, visit it, else add a
  345.      * new directory level to the menu.
  346.      */
  347.     if (!dirp)
  348.         stat = Display_File(Dir_Name, name) ;
  349.     else {
  350.         Menu_Level++ ;
  351.         (void) strncat(Dir_Name, name,
  352.             LONGEST_NAME - strlen(Dir_Name) - 1) ;
  353.         stat = Add_Dir(Dir_Name, name) ;
  354.     }
  355.     SetMenuStrip(EmW, AutoMenu) ;
  356.     return stat ;
  357. #endif    BROWSER
  358. }
  359.  
  360. #ifdef    BROWSER
  361. /*
  362.  * Display_File - Go fetch a the requested file into a window.
  363.  */
  364. Display_File(dir, file) char *dir, *file; {
  365.     register BUFFER    *bp, *findbuffer();
  366.     int        s;
  367.     char        File_Name[LONGEST_NAME];
  368.  
  369.     (void) strcpy(File_Name, dir);
  370.     (void) strncat(File_Name, file, LONGEST_NAME - strlen(File_Name) - 1) ;
  371.     if ((bp = findbuffer(File_Name, &s)) == NULL) return s;
  372.     curbp = bp;
  373.     if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
  374.     if (bp->b_fname[0] == 0)
  375.         return (readin(File_Name));        /* Read it in.    */
  376.     return TRUE;
  377.     }
  378. /*
  379.  * Add_Dir - given a dir and a name, add the menu name with the files in
  380.  *    dir as entries.  Use AllocMem() in order to make
  381.  *      sure the file info block is on a longword boundary.
  382.  */
  383. static
  384. Add_Dir(dir, name) char *dir, *name; {
  385.     register char            *last_char ;
  386.     register struct FileLock    *my_lock, *Lock() ;
  387.     unsigned short            count ;
  388.     int                stat = FALSE;
  389.     static char            Name_Buf[LONGEST_NAME] ;
  390.     char                *AllocMem();
  391.     struct    FileInfoBlock        *File_Info;
  392.  
  393.     if ((File_Info = (struct FileInfoBlock *)
  394.         AllocMem((LONG)sizeof(struct FileInfoBlock), 0L)) == NULL)
  395.         return (FALSE);
  396.  
  397.     /* Fix up the trailing / if it needs it */
  398.     last_char = &dir[strlen(dir) - 1] ;
  399.     if (*last_char == '/') *last_char = '\0' ;
  400.  
  401.     /* Now, start on the directory */
  402.     if ((my_lock = Lock(dir, ACCESS_READ)) == NULL) goto out;
  403.  
  404.     if (!Examine(my_lock, File_Info)) goto out;
  405.     if (File_Info -> fib_DirEntryType < 0L)
  406.         goto out;
  407.  
  408.     if (Menu_Add(name, TRUE) == 0) goto out;
  409.     for (count = 0; ExNext(my_lock, File_Info) 
  410.             || IoErr() != ERROR_NO_MORE_ENTRIES; count++)
  411.         if (File_Info -> fib_DirEntryType < 0L) {
  412.             if (Menu_Item_Add(File_Info -> fib_FileName,
  413.                 (USHORT)ITEMENABLED, 0L, (BYTE)0)
  414.                     == MNUM(NOMENU, NOITEM, NOSUB))
  415.                     break ;
  416.             }
  417.         else {
  418.             (void) strcpy(Name_Buf, File_Info -> fib_FileName) ;
  419.             (void) strcat(Name_Buf, "/") ;
  420.             if (Menu_Item_Add(Name_Buf,
  421.                 (USHORT) ITEMENABLED, 0L, (BYTE)0)
  422.                      == MNUM(NOMENU, NOITEM, NOSUB))
  423.                 break ;
  424.             }
  425.     if (count == 0) Menu_Item_Add("EMPTY", (USHORT)0, 0L, (BYTE)0) ;
  426.  
  427.     /* Put everything back */
  428.     if (*last_char == '\0') *last_char = '/' ;
  429.     stat = TRUE;
  430. out:
  431.     UnLock(my_lock) ;
  432.     FreeMem(File_Info, (LONG) sizeof(struct FileInfoBlock));
  433.     return stat;
  434.     }
  435.  
  436. /*
  437.  * Add all the devices currently known by the system
  438.  * to the current menu, based on the type of device
  439.  * list entry desired.  Disable multitasking while
  440.  * we look inside the device list, so we don't fly off
  441.  * into space while traversing it.
  442.  */
  443. struct DosLibrary    *DosBase;
  444. extern APTR        OpenLibrary();
  445.  
  446. static VOID
  447. Add_Devices(devtype)
  448. ULONG devtype;
  449. {
  450.     register struct DeviceList    *devlist;
  451.     struct RootNode            *rootnode;
  452.     struct DosInfo            *dosinfo;
  453.     UBYTE                buffer[80];
  454.     int                ramflag = 0;
  455.  
  456.     /* if you've gotten this far, none of these will be null. */
  457.     DosBase = (struct DosLibrary *) OpenLibrary(DOSNAME,0L);
  458.  
  459.     Forbid();            /* let's be careful out there... */
  460.     rootnode = (struct RootNode *) DosBase->dl_Root;
  461.     dosinfo = (struct DosInfo *) BADDR(rootnode->rn_Info);
  462.     devlist = (struct DeviceList *) BADDR(dosinfo->di_DevInfo);
  463.  
  464.     while (devlist) {
  465.         /* select by specified device type */
  466.         if (devlist->dl_Type != devtype) {
  467.             devlist = (struct DeviceList *) BADDR(devlist->dl_Next);
  468.             continue;
  469.         }
  470.  
  471.         /* convert device's name into AmigaDOS name and concat a ":" */
  472.         btocstr((BPTR) devlist->dl_Name,buffer,sizeof(buffer));
  473.         strcat(buffer,":");
  474.  
  475.         /* Always add volumes and assigned directories. However,
  476.          * disks should be the only devices added to the list. Magic
  477.          * disk test courtesy of Phillip Lindsay, Commodore-Amiga Inc.
  478.          */
  479.         if (devtype != DLT_DEVICE)
  480.             Menu_Item_Add(buffer,(USHORT)ITEMENABLED, 0L, (BYTE)0);
  481.         else if (devlist->dl_Task) {    /* why does this work? */
  482.             Menu_Item_Add(buffer,
  483.                 (USHORT)ITEMENABLED, 0L, (BYTE)0);
  484.             if (!strcmp(buffer,"RAM:")) ramflag = 1;
  485.         }
  486.         devlist = (struct DeviceList *) BADDR(devlist->dl_Next);
  487.     }
  488.     /* if ramdisk isn't loaded yet, add it anyway */
  489.     if ((devtype == DLT_DEVICE) && !ramflag)
  490.         Menu_Item_Add("RAM:",(USHORT)ITEMENABLED, 0L, (BYTE) 0);
  491.     Permit();
  492.     CloseLibrary(DosBase);
  493. }
  494.  
  495. btocstr(bp,buf,bufsiz)
  496. BPTR bp;
  497. char *buf;
  498. int bufsiz;
  499. {
  500.     register UBYTE    *cp;
  501.     register int    len, i;
  502.  
  503.     cp = (UBYTE *) BADDR(bp);
  504.     len = (int) *(cp++);
  505.     len = (len > bufsiz) ? bufsiz : len;    /* truncate if necessary */
  506.     for (i = 0; i < len; i++)
  507.         buf[i] = *(cp++);
  508.     buf[i] = '\0';
  509.     return (len < bufsiz);            /* return FALSE if truncated */
  510. }
  511.  
  512. #endif    BROWSER
  513.